共计 1659 个字符,预计需要花费 5 分钟才能阅读完成。
本文源于一道笔试题而来,讲一讲Java中静态代码块、非静态代码块、构造方法的执行顺序及原理:
顺序:
package cn.peiluming.test1.test1_1;
/**
* @author plm
* @create 2021/2/22 21:50
*/
public class DemoA {
public DemoA() {
System.out.println("DemoA 构造方法。");
}
{
System.out.println("DemoA 非静态代码块。");
}
static {
System.out.println("DemoA 静态代码块。");
}
}
package cn.peiluming.test1.test1_1;
/**
* @author plm
* @create 2021/2/22 21:52
*/
public class DemoB extends DemoA {
public DemoB() {
System.out.println("DemoB 构造方法。");
}
{
System.out.println("DemoB 非静态代码块。");
}
static {
System.out.println("DemoB 静态代码块。");
}
}
package cn.peiluming.test1.test1_1;
/**
* @author plm
* @create 2021/2/22 21:53
*/
public class DemoC extends DemoB {
public DemoC() {
System.out.println("DemoC 构造方法。");
}
{
System.out.println("DemoC 非静态代码块。");
}
static {
System.out.println("DemoC 静态代码块。");
}
}
package cn.peiluming.test1.test1_1;
/**
* @author plm
* @create 2021/2/22 21:54
*/
public class DemoTest {
public static void main(String[] args) {
// 简单的进行new一个对象
DemoC c = new DemoC();
}
}
/* 输出
DemoA 静态代码块。
DemoB 静态代码块。
DemoC 静态代码块。
DemoA 非静态代码块。
DemoA 构造方法。
DemoB 非静态代码块。
DemoB 构造方法。
DemoC 非静态代码块。
DemoC 构造方法。
*/
奉上代码,可简单发现执行顺序:父静态代码块 -> 子静态代码块 -> 父非静态代码块 -> 父构造方法 -> 子非静态代码块 -> 子构造方法
原理:
首先DemoC实例化时,需要调用其构造方法,那我们都知道,子类的构造方法体默认会首先执行
super()
,先加载父类;
我们之前也了解过,static
修饰的都会在类加载时先执行,所以按照类加载顺序,先执行(初始化)静态域;
指针又回到父类DemoA这儿了,为什么是先执行非静态代码块,在执行构造方法,这里有个小迷惑,我拿出DemoA的字节码文件DemoA.class,瞧一瞧:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package cn.peiluming.test1.test1_1;
public class DemoA {
public DemoA() {
System.out.println("DemoA 非静态代码块。");
System.out.println("DemoA 构造方法。");
}
static {
System.out.println("DemoA 静态代码块。");
}
}
哎呀😕,不对劲,这个非静态代码块被放到构造方法体中去了,而且最先被执行到;破案了,我们会看到先执行非静态代码块,在执行构造方法了;
子类同理;
最后:
日常开发中,非静态代码块使用较少,况且每次创建该类实例对象的时候都会执行,反观静态代码块,只在类加载的时候执行,切近会执行一次,孰优孰劣自有分晓。
正文完